import mongoose from 'mongoose'
import * as R from 'ramda'
import {changeToArr} from '../utils/common'

const User = mongoose.model('User')
const Dialog = mongoose.model('Dialog')
const Message = mongoose.model('Message')
const ObjectId = mongoose.Types.ObjectId

const userSelect = {
  _id: 1,
  nickname: 1,
  avatar: 1
}

const dialogSelect = {
  _id: 1,
  name: 1,
  icon: 1,
  meta: 1,
  createdBy: 1,
  members: 1,
  type: 1
}

// 根据用户id获取会话列表
export async function getDialogs(userId) {
  const match = [{
    $match: {
      showTo: {
        $in: [ObjectId(userId)]
      }
    }
  }, {
    $lookup: {
      from: 'messages',
      as: 'unread',
      let: { dialogId: '$_id' },
      pipeline: [{
        $match: {
          $and: [{
            $expr: { $eq: ['$dialog', '$$dialogId'] }
          }, {
            belongsTo: { $ne: ObjectId(userId) }
          }, {
            read: {
              $not: { $all: [ObjectId(userId)] }
            }
          }]
        }
      }, {
        $count: 'count'
      }]
    }
  }, {
    $lookup: {
      from: 'users',
      as: 'toUser',
      let: { userIds: '$members' },
      pipeline: [{
        $match: {
          $and: [
            {$expr: {$in: ['$_id', '$$userIds']}},
            { _id: {$ne: ObjectId(userId)} }
          ]

        }
      }, {
        $limit: 1
      }, {
        $project: {
          icon: '$avatar',
          name: '$nickname',
          _id: 1
        }
      }]
    }
  }, {
    $lookup: {
      from: 'messages',
      as: 'message',
      let: { dialogId: '$_id' },
      pipeline: [{
        $match: {
          $expr: {
            $eq: ['$dialog', '$$dialogId']
          }
        }
      }, {
        $sort: {
          'meta.createdAt': -1
        }
      }, {
        $limit: 1
      }, {
        $project: {
          content: 1,
          meta: 1,
          belongsTo: 1
        }
      }]
    }
  }, {
    $match: {
      message: {
        $gt: [{$size: '$message'}, 0]
      }
    }
  }, {
    $sort: {
      'message.meta.createdAt': -1
    }
  }, {
    $project: {
      message: {$arrayElemAt: ['$message', 0]},
      meta: 1,
      type: 1,
      head: {
        $cond: {
          if: {
            $and: [{
              $eq: ['$type', 0]
            }, {
              $gt: [{$size: '$toUser'}, 0]
            }]
          },
          then: {
            $arrayElemAt: ['$toUser', 0]
          },
          else: {
            $let: {
              vars: {},
              in: {
                name: '$name',
                icon: '$icon'
              }
            }
          }
        }
      },
      unread: {
        $cond: {
          if: {$gt: [{$size: '$unread'}, 0]},
          then: {
            $let: {
              vars: {
                size: {$arrayElemAt: ['$unread', 0]}
              },
              in: '$$size.count'
            }
          },
          else: 0
        }
      },
      _id: 1
    }
  }]
  const count = await Dialog.aggregate([...match, {$count: 'total'}])
  const total = count.length ? count[0].total : 0
  const dialogs = await Dialog.aggregate([...match])
  return {
    data: dialogs,
    total,
    unread: R.sum(dialogs.map(item => item.unread)),
    result: 1,
    mes: '获取成功'
  }
}

export async function getUnreadCountByUserId(userId) {
  const counts =  await Dialog.aggregate([{
    $match: {
      showTo: {
        $all: [ObjectId(userId)]
      }
    }
  }, {
    $lookup: {
      from: 'messages',
      as: 'unread',
      let: { dialogId: '$_id' },
      pipeline: [{
        $match: {
          $and: [{
            $expr: { $eq: ['$dialog', '$$dialogId'] }
          }, {
            belongsTo: { $ne: ObjectId(userId) }
          }, {
            read: {
              $not: { $all: [ObjectId(userId)] }
            }
          }]
        }
      }, {
        $count: 'count'
      }]
    }
  }, {
    $project: {
      unread: {
        $cond: {
          if: {$gt: [{$size: '$unread'}, 0]},
          then: {
            $let: {
              vars: {
                size: {$arrayElemAt: ['$unread', 0]}
              },
              in: '$$size.count'
            }
          },
          else: 0
        }
      }
    }
  }])
  return R.sum(counts.map(item => item.unread))
}

export async function getDialogInfoByDialogId(id, userSelectExtra = {}) {
  return await Dialog.findOne({
    _id: ObjectId(id)
  }).populate({
    path: 'members',
    select: {
      ...userSelect,
      ...userSelectExtra
    }
  }).populate({
    path: 'createdBy',
    select: {
      ...userSelect,
      ...userSelectExtra
    }
  }).select({
    ...dialogSelect
  })
}

// 创建聊天室
export async function createDialog(belongsTo, userIds, name) {
  const users = await User.find({
    _id: {
      $in: userIds.map(item => ObjectId(item))
    }
  })
  const dialog = new Dialog({
    type: 1,
    createdBy: ObjectId(belongsTo),
    members: [ObjectId(belongsTo)].concat(users.map(item => item._id)),
    name
  })
  await dialog.save()
}

// 我加入&创建的群组
export async function getMyDialogs(userId) {
  return await Dialog.find({
    type: 1,
    members: {
      $all: [ObjectId(userId)]
    }
  }).select({
    _id: 1,
    name: 1,
    icon: 1,
    meta: 1,
    createdBy: 1
  })
}

// 从会话列表中删除
export async function hideDialog(userId, dialogId) {
  await Dialog.updateOne({
    _id: ObjectId(dialogId)
  }, {
    $pull: {
      showTo: {$in: [ObjectId(userId)]}
    }
  })
}

// 退出群组
export async function exitDialog(userIds, dialogId) {
  const users = changeToArr(userIds).map(item => ObjectId(item))
  await Dialog.updateOne({
    _id: ObjectId(dialogId),
    createdBy: {
      $nin: users
    }
  }, {
    $pull: {
      members: {$in: users},
      showTo: {$in: users}
    }
  })
}

// 解散群组
export async function delDialog(userId, dialogId) {
  const dialog = await Dialog.findOneAndDelete({
    _id: ObjectId(dialogId),
    createdBy: ObjectId(userId)
  })
  if (dialog) {
    await Message.deleteMany({
      dialog: ObjectId(dialogId)
    })
  }
}

// 加入群组
export async function joinDialog(userIds, dialogId) {
  const users = await User.find({
    _id: {
      $in: changeToArr(userIds).map(item => ObjectId(item))
    }
  })
  await Dialog.updateOne({
    _id: ObjectId(dialogId)
  }, {
    $addToSet: {
      members: {$each: users.map(item => item._id)}
    }
  })
}

// 修改聊天室名称
export async function updateDialogName(userId, dialogId, name) {
  await Dialog.updateOne({
    _id: ObjectId(dialogId),
    createdBy: ObjectId(userId)
  }, {
    $set: {
      name
    }
  })
}

// 修改聊天室图标
export async function updateDialogIcon(userId, dialogId, icon) {
  await Dialog.updateOne({
    _id: ObjectId(dialogId),
    createdBy: ObjectId(userId)
  }, {
    $set: {
      icon
    }
  })
}
